iT邦幫忙

2025 iThome 鐵人賽

DAY 30
0
Modern Web

Laravel 是甚麼系列 第 30

安裝EXCEL套件

  • 分享至 

  • xImage
  •  

https://docs.laravel-excel.com/3.1/getting-started/installation.html
https://ithelp.ithome.com.tw/upload/images/20251006/201190354XVGAxgrJm.png

composer require maatwebsite/excel

https://ithelp.ithome.com.tw/upload/images/20251006/20119035Mb8mwsLO00.png
最下面

https://ithelp.ithome.com.tw/upload/images/20251006/20119035TRe1xW2HSz.png

https://ithelp.ithome.com.tw/upload/images/20251006/20119035NLqHkZGT3e.png
貼上


php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider" --tag=config

https://ithelp.ithome.com.tw/upload/images/20251006/2011903506FRBdOKr1.pnghttps://ithelp.ithome.com.tw/upload/images/20251006/20119035UUKmaJcih1.png

會產生兩個資料夾
https://docs.laravel-excel.com/3.1/architecture/objects.html
https://ithelp.ithome.com.tw/upload/images/20251006/20119035PWuzquw1Ln.png
下指令

php artisan make:export OrdersExport --model=Order

https://ithelp.ithome.com.tw/upload/images/20251006/20119035dSznEnJAVM.png
產生資料夾跟檔案
https://ithelp.ithome.com.tw/upload/images/20251006/20119035sgobQsqTt1.png

https://ithelp.ithome.com.tw/upload/images/20251006/20119035RIS3HmKjCd.png

修改裡面的程式碼
下面
https://ithelp.ithome.com.tw/upload/images/20251006/20119035XbWsiNvJ8i.png
最前面
https://ithelp.ithome.com.tw/upload/images/20251006/20119035uCda2HRwAW.png
修改後的程式碼

<?php

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;
use App\Models\Order;
use App\Http\Controllers\Controller;
use App\Notifications\OrderDelivery;
use Maatwebsite\Excel\Facades\Excel;
use App\Exports\OrdersExport; // ← 加這行
class OrderController extends Controller
{
    

    public function index(Request $request)
{

    $dataPerPage = 5;
        
        $orders = Order::with(['orderItems', 'orderItems.product', 'user'])
                      ->orderBy('created_at', 'desc')
                      ->whereHas('orderItems')
                      ->paginate($dataPerPage);
        
        return view('admin.orders.index', [
            'orders' => $orders,
            'orderCount' => Order::whereHas('orderItems')->count(),
        ]);

}

public function delivery($id)
{
    $order = Order::find($id);
    if ($order->is_shipped) {
        return response(['result' => false]);
    } else {
        $order->update(['is_shipped' => true]);
        $order->user->notify(new OrderDelivery());
        return response(['result' => true]);
    }

}

public function export()
{
    return Excel::download(new OrdersExport,'orders.xlsx');
}

}

前端畫面加入

<div>
  <a href="/admin/orders/excel/export">匯出訂單</a>
</div>

https://ithelp.ithome.com.tw/upload/images/20251006/201190358WsIGDvlWb.png
加入路由

Route::get('admin/orders/excel/export', 'Admin\OrderController@export');

要再執行一次畫面才會更新
https://ithelp.ithome.com.tw/upload/images/20251006/20119035Dy2Z9x5Sx7.png
php artisan serve
畫面上面顯示
https://ithelp.ithome.com.tw/upload/images/20251006/20119035N0qFT2RfEV.png
按 下載檔案 顯示
https://ithelp.ithome.com.tw/upload/images/20251006/20119035d05K4RekGL.png
對照資料表的內容
https://ithelp.ithome.com.tw/upload/images/20251006/20119035o2ax2r18yp.png
加入表頭的顯示
修改程式碼
https://ithelp.ithome.com.tw/upload/images/20251006/20119035UCDlQbXYHJ.png
程式碼

<?php

namespace App\Exports;

use Illuminate\Support\Facades\Schema;
use App\Models\Order;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;

class OrdersExport implements FromCollection,WithHeadings
{
    /**
    * @return \Illuminate\Support\Collection
    */
    public function collection()
    {
        return Order::all();
    }
    public function headings():array
    {
        return Schema::getColumnListing('orders');
    }
}

畫面上再匯出一次
https://ithelp.ithome.com.tw/upload/images/20251006/201190351bJ9pOYs0Y.png
顯示
https://ithelp.ithome.com.tw/upload/images/20251006/20119035bNZnBQPkmp.png

目前的錯誤:
Error: Interface "Maatwebsite\Excel\Facades\WithHeadings" not found
❌ 問題根本原因
你寫成了:
use Maatwebsite\Excel\Facades\WithHeadings;
但 WithHeadings 不是 Facade,它是一個 介面(interface),應該從 Maatwebsite\Excel\Concerns 匯入。


✅ 正確寫法
請把這一行:
use Maatwebsite\Excel\Facades\WithHeadings;
改成這樣:
use Maatwebsite\Excel\Concerns\WithHeadings;


✅ 完整修正後的 OrdersExport.php

<?php

namespace App\Exports;

use Illuminate\Support\Facades\Schema;
use App\Models\Order;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;

class OrdersExport implements FromCollection, WithHeadings
{
    /**
     * @return \Illuminate\Support\Collection
     */
    public function collection()
    {
        return Order::all();
    }

    public function headings(): array
    {
        return Schema::getColumnListing('orders');
    }
}

✅ 延伸提醒

  1. 如果你使用的是 Order::all(),那匯出的資料會包含所有欄位,建議先確認是否需要過濾部分欄位或加上排序。
  2. Schema::getColumnListing('orders') 是抓資料表欄位名稱,會以資料表原始欄位為主(如 user_id, created_at 這類資料庫名稱)。

如果你想讓欄位名稱是比較友善的,例如「訂購人」、「金額」這類中文名稱,也可以改寫成:
public function headings(): array
{
return ['訂單 ID', '用戶 ID', '是否已出貨', '建立時間', '更新時間'];
}


加入:匯入:按鈕
修改前程式碼

@extends('layouts.admin_app')
@section('content')
<h2>產品列表</h2>
<span>產品總數: {{ $productCount }} </span>
<table>
  <thead>
    <tr>
      <td>編號</td>
      <td>標題</td>
      <td>內容</td>
      <td>價格</td>
      <td>數量</td>
      <td>圖片</td>
      <td>功能</td>
    </tr>
  </thead>
  <tbody>
    @foreach( $products as $product )
      <tr>
        <td>{{ $product->id }}</td>
        <td>{{ $product->title }}</td>
        <td>{{ $product->content }}</td>
        <td>{{ $product->price }}</td>
        <td>{{ $product->quantity }}</td>     
        

        <td>
  @if($product->images->isNotEmpty())
    <a href="{{ asset('storage/' . $product->images->first()->path) }}">圖片連結</a>
  @else
    無圖片
  @endif
</td>
        <td>
            <input type="button" class="upload_image" data-id="{{ $product->id }}" value="上傳圖片">
        </td>
      </tr>
    @endforeach
  </tbody>
</table>
<div>
  @for ($i = 1; $i <= $productPages; $i++)
      <a href="/admin/products?page={{ $i }}">第 {{ $i }} 頁</a> &nbsp;
  @endfor
</div>

<!-- Add Modal for Image Upload -->
<div class="modal fade" id="upload_image_modal" tabindex="-1" role="dialog" aria-labelledby="uploadImageModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="uploadImageModalLabel">上傳圖片</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <!-- <form id="upload_form" method="POST" enctype="multipart/form-data">-->
        <form id="upload_form" method="POST" action="/admin/products/upload-image" enctype="multipart/form-data">

          @csrf
          <input type="hidden" id="product_id" name="product_id">
          <div class="form-group">
            <label for="product_image">選擇圖片</label>
            <input type="file" class="form-control" id="product_image" name="product_image">
          </div>
          <button type="submit" class="btn btn-primary">上傳</button>
        </form>
      </div>
    </div>
  </div>
</div>

<script>
$(document).ready(function() {
  $('.upload_image').click(function() {
    $('#product_id').val($(this).data('id'));
    $('#upload_image_modal').modal('show');
  });
});
</script>
@endsection

大家明年見~


上一篇
有的四個網址
系列文
Laravel 是甚麼30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言